import { useState, useEffect } from 'react';
import { usePersistFn } from 'ahooks';
import useStateRef from 'react-usestateref';
import { debounce } from 'lodash';

/**
 * @param {string} path 路径
 * @param {string} msgType 传参类型 <json|jsonstring>
 * @param {function} onMessage 消息回调
 * @param {object} heartCheckMsg 心跳检测发送数据 有发送多条的需求可改为数组
 * @param {array} openMsg 初始化连接后发送的数据
 * @param {array} closeMsg 断开连接前发送的数据
 * @returns {object} {ws, connect, send, disconnect}
 */
const useWebSocket = ({ path, msgType = 'json', onMessage, heartCheckMsg, openMsg = [], closeMsg = [] }) => {
  const [openMsgQueue, setOpenMsgQueue] = useState(openMsg);
  const [closeMsgQueue, setCloseMsgQueue] = useState(closeMsg);
  const [, setWs, ws] = useStateRef(null);
  const [, setStatus, status] = useStateRef(null);
  const [, setReconnetCount, reconnetCount] = useStateRef(5); // 重连次数
  const [, setTimer, timer] = useStateRef(null);
  // const { WEBSOCKET_PUSH_API } = process.env;
  // eslint-disable-next-line
  const WEBSOCKET_PUSH_API = process.env.WEBSOCKET_PUSH_API;
  // 判断是否需要走代理
  const wsapi = /^(ws|wss)/.test(WEBSOCKET_PUSH_API) ? WEBSOCKET_PUSH_API : `ws://${global.location.host}${WEBSOCKET_PUSH_API}`;
  const socketUrl = `${wsapi}/websocket/${path}`;

  // 发送数据
  const send = usePersistFn((data) => {
    if (status.current === 'open' && ws.current?.send) {
      ws.current.send(msgType === 'jsonString' ? JSON.stringify(data) : data);
    } else {
      setOpenMsgQueue([...openMsgQueue, data]);
    }
  });

  // ws连接
  const connect = usePersistFn(() => setWs(new WebSocket(socketUrl)));

  // 连接成功回调
  const afterOnopen = usePersistFn(() => {
    if (openMsgQueue?.length) {
      openMsgQueue.forEach((data) => send(data));
      setOpenMsgQueue([]);
    }
  });
  // 清除定时器
  const clearTimer = usePersistFn(() => {
    clearInterval(timer.current);
    setTimer(null);
  });
  // 心跳检测
  const heartCheck = usePersistFn(() => {
    clearTimer();
    if (heartCheckMsg) {
      setTimer(setInterval(() => {
        send(heartCheckMsg);
      }, 30000));
    }
  });
  const onopen = usePersistFn(() => {
    setStatus('open');
    afterOnopen();
    heartCheck();
  });

  // 消息监听
  const onmessage = usePersistFn(({ data }) => onMessage(data));

  // 关闭之前调用
  const beforeDisconnect = usePersistFn(() => {
    if (closeMsgQueue?.length) {
      closeMsgQueue.forEach((data) => send(data));
      setCloseMsgQueue([]); // 清空消息
    }
  });

  // 关闭ws
  const disconnect = usePersistFn(() => {
    beforeDisconnect();
    setOpenMsgQueue([]); // 清空初始化消息
    clearTimer();
    setStatus('close');
    ws.current?.close();
    setWs(null);
  });

  // ws重连
  const reconnect = usePersistFn(debounce(() => {
    if (status.current === 'close') return;
    if (reconnetCount.current > 0) {
      setReconnetCount(reconnetCount.current - 1);
      connect();
    }
  }, 100));
  // ws关闭
  const onclose = usePersistFn(() => reconnect());
  // ws错误
  const onerror = usePersistFn(() => reconnect());

  useEffect(() => {
    if (ws.current) {
      ws.current.onopen = onopen;
      ws.current.onmessage = onmessage;
      ws.current.onclose = onclose;
      ws.current.onerror = onerror;
    }
  }, [ws.current]);

  return {
    ws: ws.current,
    connect,
    send,
    disconnect,
  };
};

export default useWebSocket;
